package labox.innovation.gameserver.model;

import java.util.Map;
import java.util.Set;

import javolution.util.FastMap;

import labox.innovation.gameserver.datatables.SkillTable;
import labox.innovation.gameserver.model.actor.instance.FuzePcInstance;


/**
 *  技能物品 冷却 管理类
 *  技能冷却的时间 单位 都为 毫秒
 *  @author zjj
 *
 */
public class FuzeSkillCoolDown {
	
	protected long _globalCooldown; //公共冷却时间
	
	protected FuzePcInstance _owner;
	
	/**
	 *  key : 为冷却类型
	 *  value : 属性为冷却类型的 技能id
	 */
	
	protected Map<Integer, Set<Integer> > _spellCategory; //技能冷却类型
	
	/**
	 * key : 为冷却的技能Id
	 */
	protected Map<Integer, TimeStamp> _skillCoolDownMap;  //所有技能的冷却表
	
	/**
	 * key : 为技能的冷却类型
	 * val : 为类型冷却的结束时间
	 * 每个技能上应该带有个 类型冷却时间。 如果确实需要的话
	 * 且每个类型的冷却时间 在各个技能上是一样的 ， 因为他们同属于一种类型冷却
	 */
	protected Map<Integer, Long> _skillCategoryCool; //所有技能类别的冷却时间
	
	
	/**
	 * 技能使用时 的时间戳
	 * @author zjj
	 *
	 */
	public static class TimeStamp{
		public int _itemId;
		public int _reuseTime; //在使用时间
		public long _stamp;    //end Time, 在使用结束时间
		public int _skillId;
		
		public TimeStamp( int skillId, int reusetime )
		{
			_itemId = -1;
			_reuseTime = reusetime;
			_stamp = System.currentTimeMillis() + _reuseTime;
			_skillId = skillId;
		}
		
		public TimeStamp( int skillId, int itemId, int reusetime )
		{
			_itemId = itemId;
			_reuseTime = reusetime;
			_stamp = System.currentTimeMillis() + _reuseTime;
			_skillId = skillId;
		}
		
		public TimeStamp( int skillId, int reusetime, long endtime )
		{
			_itemId = -1;
			_reuseTime = reusetime;
			_stamp = endtime;
			_skillId = skillId;
		}
		
		public TimeStamp( int skillId, int itemId, int reusetime, long endtime )
		{
			_itemId = itemId;
			_reuseTime = reusetime;
			_stamp = endtime;
			_skillId = skillId;
		}
		
		/**
		 * 技能剩余的冷却时间
		 * @return
		 */
		public long getRemaining() 
		{
			return Math.max(_stamp - System.currentTimeMillis(), 0);
		}
		
		public boolean hasNotPassed() {
			if (System.currentTimeMillis() < _stamp) {
				return true;
			}
			return false;
		}
		
		public long getStamp() {
			return _stamp;
		}

		public int getItemId() {
			return _itemId;
		}
		
		public int getSkill()
		{
			return _skillId;
		}

		public int getReuse() {
			return _reuseTime;
		}
	
		
	}// end class TimeStamp
	
	
	public FuzeSkillCoolDown( FuzePcInstance owner )
	{
		_owner = owner;
		_skillCoolDownMap = new FastMap<Integer, TimeStamp>();
		_skillCategoryCool = new FastMap<Integer, Long>();
		_globalCooldown = 0;
	}
	
	/**
	 * 更新技能的公共冷去时间
	 * @param diff : 更新的插值
	 */
	public void update( int diff )
	{
		if( _globalCooldown <= diff )
			_globalCooldown = 0;
		else
			_globalCooldown -= diff;
	}
	
	/**
	 * 移除指定技能的时间戳
	 * @param skillId
	 */
	public void removeSkillCoolTime( int skillId )
	{
		_skillCoolDownMap.remove( skillId );
	}
	
	/**
	 * 增加技能时间戳
	 * @param skillId
	 * @param ts
	 */
	protected void addSkillCoolTime( int skillId , TimeStamp ts )
	{
		_skillCoolDownMap.put( skillId, ts );
	}
	
	protected void addSkillCoolTime( int skillId, int itemId, int reusetime )
	{
		_skillCoolDownMap.put( skillId, new TimeStamp(skillId, itemId, reusetime) );
	}
	
	protected void addSkillCoolTime( int skillId, int itemId, int reusetime, long endtime  )
	{
		_skillCoolDownMap.put( skillId, new TimeStamp(skillId, itemId, reusetime, endtime) );
	}
	
	/**
	 * 增加技能到冷却队列
	 * @param skillId
	 * @param itemId
	 */
	public void addSkillCoolDown( int skillId, int itemId )
	{
		L2Skill skill = _owner.getSkill( skillId );
		addSkillCoolDown( skill, itemId );
	}
	
	/**
	 *  增加技能到冷却队列
	 *  技能的冷却时间 由技能配置所得， 不受修改
	 * @param sk 
	 * @param itemId
	 */
	public void addSkillCoolDown( L2Skill sk, int itemId )
	{
		int reuse = sk.getReuseDelay();
		
		addSkillCoolDown( sk, itemId, reuse);
//		if( reuse > 0 )
//		{
//			addSkillCoolTime( sk.getId(), itemId, reuse );
//		}
//			
//		if( sk.getSkillCategory() >= 0 )
//		{
//			addSkillCategoryCoolDown( sk.getSkillCategory(), sk.getSkillCategoryReuseTime() + System.currentTimeMillis() );
//		}
//
//		_globalCooldown = System.currentTimeMillis() + sk.getCoolTime();
	}
	
	/**
	 * 增加技能到冷却队列
	 * 技能的冷却时间 外部计算所得， 不获取技能配置的技能冷却时间
	 * @param sk
	 * @param itemId
	 * @param reuse  : 在使用时间
	 */
	public void  addSkillCoolDown( L2Skill sk, int itemId , int reuse )
	{
		int time = reuse > sk.getSkillCategoryReuseTime()?reuse:sk.getSkillCategoryReuseTime();
		if( time > 0 )
		{
			addSkillCoolTime( sk.getId(), itemId, time );
		}
			
		if( sk.getSkillCategory() >= 0 )
		{
			addSkillCategoryCoolDown( sk.getSkillCategory(), sk.getSkillCategoryReuseTime() + System.currentTimeMillis() );
		}
		
		_globalCooldown = System.currentTimeMillis() + sk.getCoolTime();
	}
	
	
	/**
	 * 用于数据库恢复 技能冷却，  这个函数不增加不会影响公共冷却时间
	 * 除了数据库恢复，其他函数不应该调用这个函数
	 * @param sk
	 * @param itemId
	 * @param reuse
	 * @param catcool  : 类型冷却时间
	 */
	public void  addSkillCoolDown( int skId, int itemId , int reuse, int catcool )
	{
		if( reuse > 0 )
		{
			addSkillCoolTime( skId, itemId, reuse );
		}
		
		L2Skill sk = SkillTable.getInstance().getInfo(skId, 1);
		if( sk.getSkillCategory() >= 0 && catcool > 0 )
		{
			addSkillCategoryCoolDown( sk.getSkillCategory(), catcool + System.currentTimeMillis() );
		}
		
	}
	
	/**
	 *  增加技能的类型冷却时间
	 * @param cat   : 技能冷却类型
	 * @param apply_time :开始时间
	 */
	protected void addSkillCategoryCoolDown( int cat, long apply_time )
	{
		_skillCategoryCool.put( cat , apply_time );
	}
	
	
	/**
	 *  技能是否在冷却中
	 *  true 冷却中 false冷却结束
	 * @param skill
	 * @return 
	 */
	public boolean isSkillCoolDown( L2Skill skill )
	{
		TimeStamp ts = _skillCoolDownMap.get( skill.getId() );
		return ( ( ts != null &&  ts.hasNotPassed() ) || isSkillCategoryCoolDown( skill ) );
	}
	
	/**
	 *  技能冷却类型是否在冷却中
	 * @param skill
	 * @return
	 */
	public boolean isSkillCategoryCoolDown( L2Skill skill )
	{
//		L2Skill skill = _owner.getSkill( skillId );
		
		//技能有公共冷却类型， 且公共CD还处于冷却中 
		if( skill.getStartCoolTimeCategory() > 0 && _globalCooldown > System.currentTimeMillis() )
		{
			return true;
		}
		
		//类型冷却时间
		Long catrec = _skillCategoryCool.get( skill.getSkillCategory() );
		
		return ( catrec != null && catrec > System.currentTimeMillis() );
		
	}
	
	public boolean isSkillCategoryCoolDown( int skillid )
	{
		L2Skill skill = SkillTable.getInstance().getInfo(skillid, 1);
		if( skill == null )
		{
			return false;
		}
		
		return isSkillCategoryCoolDown( skill );
	}
	
	/*(*
	 * 获得技能的 使用时间戳
	 */
	public TimeStamp getSkillCoolTimeStamp( int skillId )
	{
		return _skillCoolDownMap.get( skillId ); 
	}
	
	/**
	 *  获得技能类型冷却时间
	 * @param cat
	 * @return
	 */
	public long getSkillCatCoolTimeStamp( int cat)
	{
		return _skillCategoryCool.get( cat );
	}

	
	/**
	 *  获得技能剩余的冷去时间
	 * @param id
	 * @return
	 */
	public int getSkillCoolTime( L2Skill sk )
	{
		int reuseTime = 0;
		TimeStamp ts = getSkillCoolTimeStamp( sk.getId() );
		if( ts != null )
			reuseTime = (int)ts.getRemaining() ;
		

		if( reuseTime < getSkillCatCoolTime( sk.getSkillCategory() ) )
		{
			reuseTime = (int)getSkillCatCoolTime( sk.getSkillCategory() );
		}
		
		if( reuseTime < getSkillCoolDownTime() )
		{
			reuseTime = getSkillCoolDownTime();
		}
		
		return reuseTime;
		
	}
	
	/**
	 *  获得 剩余公共CD时间
	 * @return
	 */
	public int getSkillCoolDownTime()
	{
		return (int)( _globalCooldown - System.currentTimeMillis() );
	}
	
	/**
	 * 获得技能类型冷去的 剩余时间
	 * @return
	 */
	public int getSkillCatCoolTime( int cat )
	{
		if( _skillCategoryCool.get( cat ) == null )
		{
			return 0;
		}
		
		return (int)( _skillCategoryCool.get( cat ) - System.currentTimeMillis() );
	}
	
	public long getSkillCatCoolTimeById( int skillId )
	{
		L2Skill skill = SkillTable.getInstance().getInfo(skillId, 1);
		if( skill == null )
		{
			return 0;
		}
		
		return getSkillCatCoolTime( skill.getSkillCategory() );
	}
	
	
	/**
	 * 所有技能时间戳
	 * @return
	 */
	public Map<Integer, TimeStamp> getSkillTimeStamps()
	{
		return _skillCoolDownMap;
	}
	
}
